package com.kevis.zhunblog.admin.security.filter;

import com.kevis.common.constant.ServletConstant;
import com.kevis.zhunblog.admin.security.entity.SecurityUser;
import com.kevis.zhunblog.admin.security.service.ZhunAccessDecisionManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.security.access.SecurityMetadataSource;
import org.springframework.security.access.intercept.InterceptorStatusToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@Order(0)
@Component
public class DynamicSecurityFilter extends FilterSecurityInterceptor {
    @Resource
    private SecurityMetadataSource dynamicSecurityMetadataSource;

    @Autowired
    public void setAccessDecisionManager(ZhunAccessDecisionManager accessDecisionManager) {
        super.setAccessDecisionManager(accessDecisionManager);
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //super.doFilter(request, response, chain);
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        FilterInvocation fi = new FilterInvocation(servletRequest, servletResponse, filterChain);
        //OPTIONS请求直接放行
        if (request.getMethod().equals(HttpMethod.OPTIONS.toString())) {
            fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
            return;
        }
        String servletPath = request.getServletPath();
        //这边拦截静态资源，因为后续权限不需要判断静态资源的。不过后续应该把静态资源放到nginx，这样就不会进入了，节省java的处理
        PathMatcher pathMatcher = new AntPathMatcher();
        List<String> listStaticRecourse = new ArrayList<String>(
                Arrays.asList("/**/*.js", "/**/*.css", "/**/*.jpg", "/**/*.png", "/**/*.gif", "/**/*.map", "/**/*.html", "/**/*.ico"
                        , "/**/*.svg", "/**/*.eot", "/**/*.ttf", "/**/*.woff", "/**/*.woff2"//字体文件
                        , "/**/*.yml"));

        for (String s : listStaticRecourse) {
            if (pathMatcher.match(s, servletPath)) {
                fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
                return;//不继续了，不然会继续到 SecurityMetadataSource类
            }
        }
        //白名单请求直接放行,如果是前台会员的系统,可以用路由来拦截放行,例如 /admin/** 这种路由的就不放行,其他的地址放行.或者 /web/** 这种地址放行,其他的地址不放行
        List<String> listOtherRecourse = new ArrayList<String>(Arrays.asList("/", "/index", "/console", "/system/menu/data", "/login"
                , "/code/image", "/error/**"
                , "/swagger-ui/index.html/**", "/swagger-resources/**", "/v2/api-docs"//放行 swagger的请求,这样才能展示这个页面,不然就会死循环了
        ));
        for (String s : listOtherRecourse) {
            if (pathMatcher.match(s, servletPath)) {
                fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
                return;//不继续了，不然会继续到 SecurityMetadataSource类
            }
        }

//        PathMatcher pathMatcher = new AntPathMatcher();
//        for (String path : ignoreUrlsConfig.getUrls()) {
//            if(pathMatcher.match(path,request.getRequestURI())){
//                fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
//                return;
//            }
//        }
        ServletConstant.SERVER_SERVLET_CONTEXTPATH = request.getContextPath();
        //判断是否超管角色进来,超管的不需要进行权限控制
        Object authentication = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        //还没登录的时候, authentication 值是 anonymousUser
//        if("anonymousUser".equalsIgnoreCase(authentication)){
//            fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
//            return;
//        }
        //String userName = ((UserDetails) authentication).getUsername();
        int roleId = ((SecurityUser) authentication).getRoleId();
        if (roleId == 9999) {
            fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
            return;
        }
        //此处会调用AccessDecisionManager中的decide方法进行鉴权操作
        InterceptorStatusToken token = super.beforeInvocation(fi);
        try {
            fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
        } finally {
            super.afterInvocation(token, null);
        }
    }

    @Override
    public void destroy() {
        //super.destroy();
    }

    @Override
    public Class<?> getSecureObjectClass() {
        return FilterInvocation.class;
    }

    @Override
    public SecurityMetadataSource obtainSecurityMetadataSource() {
        return dynamicSecurityMetadataSource;
    }
}
